StupidBeauty
Read times:2610Posted at: - no title specified

Fruit教程翻译: 3. 有辅助的注入 3. Assisted injection

在教程的这个部分,我们会构造 一个组件,它的作用是, 按照某个常数因子 ,将双精度浮点数放大对应的倍数。完整 的源代码在这里: examples/scaling_doubles

首先,编写一个Multiplier 组件。

// multiplier.h

class Multiplier {
public:
  // 返回 x和y的乘积。
  virtual double multiply(double x, double y) = 0;
};

fruit::Component<Multiplier> getMultiplierComponent();

// multiplier.cpp

#include "multiplier.h"

class MultiplierImpl : public Multiplier {
public:
  double multiply(double x, double y) override {
    return x * y;
  }
};

fruit::Component<Multiplier> getMultiplierComponent() {
  return fruit::createComponent()
    .bind<Multiplier, MultiplierImpl>()
    .registerConstructor<MultiplierImpl()>();
}

如本例所示,如果某个接口存在着一个标准实现,那么,我们可以将该接口的定义和get*Component()函数的声明放置在同一个头文件中,以省掉一些繁琐的代码。

注意 MultiplierImpl 的构造函数 并未 使用 INJECT() 包装起来 那是一种用来向Fruit 告知 该使用哪个注入器的便利方式,但是, 在某些情况下,无法使用那种方式,例如, MultiplierImpl可能 是由另一个并未使用Fruit 的项目提供的。 本示例中,我们实际上可以使用那种方式,但是, 我们就是不使用,以展示 另一种(等价的)方式,即,显式地使用构造函数 的原型来调用registerConstructor。

// scaler.h

class Scaler {
public:
  virtual double scale(double x) = 0;
};

using ScalerFactory = std::function<std::unique_ptr<Scaler>(double)>;

fruit::Component<ScalerFactory> getScalerComponent();

一开始,妳可能争着要去编写 Component<Scaler> 。但是, 我们并没有单个的 Scaler实现,而且,对于每个 双精度浮点数值(即为因子),都存在一个 Scaler实现 。所以 ,我们在组件原型中暴露这一点。 在返回数值类型时, 我们可以直接以数值的形式来返回,但是 ,对于接口来说,最好 是返回一个 unique_ptr ,以确保 该对象会被销毁。 Fruit 可以注入任意类,但是 ,对于像 std::function<std::unique_ptr<T>(...)> 这种形式的类型,有着特殊的支持,我们狠快会看到。
现在开始
写实现代码。

// scaler.cpp

#include "scaler.h"
#include "multiplier.h"

using fruit::Component;
using fruit::Injector;
using fruit::createComponent;

class ScalerImpl : public Scaler {
private:
  Multiplier* multiplier;
  double factor;

public:
  INJECT(ScalerImpl(ASSISTED(double) factor, Multiplier* multiplier))
    : multiplier(multiplier), factor(factor) {
  }

  double scale(double x) override {
    return multiplier->multiply(x, factor);
  }
};

Component<ScalerFactory> getScalerComponent() {
  return createComponent()
    .bind<Scaler, ScalerImpl>()
    .install(getMultiplierComponent());
}

此处 ,我们首次见到了 ASSISTED() 宏。 它的作用是, 在一个被 INJECT() 包装的构造函数中,标记 出某些不需要被注入的类型,那些类型 会成为被注入的工厂函数的参数。

注意,此处,我们直接安装了这个乘法器组件,而不是将它声明为需求再编写一个将ScalerImplComponent 和MultiplierComponent 复合起来的组件。这是一个折衷:这样做,会稍微削弱模块化特性,但是,会使代码更简洁(避免写出2个文件)。至于空间哪种实现方式更好呢,没有绝对的答案;这种折衷,必须根据具体的情况来评估。

注意 ,此处绑定操作也做了某些不同的事情: 我们没有将 Scaler绑定 ScalerImpl 而是将一个 std::function<std::unique_ptr<Scaler>(double)> 绑定到一个 std::function<std::unique_ptr<ScalerImpl>(double)>

// main.cpp

#include "scaler.h"

using fruit::Injector;

int main() {
  Injector<ScalerFactory> injector(getScalerComponent());
  ScalerFactory scalerFactory(injector);

  std::unique_ptr<Scaler> scaler = scalerFactory(12.1);
  std::cout << scaler->scale(3) << std::endl;

  return 0;
}

这就 main() 函数,现在应该 狠容易理解了。 我们从注入器获取了工厂的一个实例,然后,自己调用 该工厂的方法来获取Scaler 的一个实例。

现在,妳已经知道Fruit 的基本用法了。为了进一步熟悉它呢,建议妳尝试着重写上面展示的系统,或者,编写妳觉得有意思的任何其它系统,再改动一下代码,观摩其效果。

教程 的下一部分 中,我们将学习 到,Fruit 是如何报告注入错误的。

Your opinions
Your name:Email:Website url:Opinion content:
- no title specified

HxLauncher: Launch Android applications by voice commands

 
Recent comments
2017年4月~2019年4月垃圾短信排行榜Posted at:Thu Sep 26 04:51:48 2024
Qt5.7文档翻译:QWebEngineCookieStore类,QWebEngineCookieStore ClassPosted at:Fri Aug 11 06:50:35 2023盲盒kill -9 18289 Grebe.20230517.211749.552.mp4